package com.yanqu.road.server.gameplayer.module.hunt;

import com.yanqu.road.entity.config.hunt.HuntMonster;
import com.yanqu.road.entity.enums.eBigRankType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.eRankType;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.entity.hunt.HuntBattleResult;
import com.yanqu.road.entity.hunt.HuntBox;
import com.yanqu.road.entity.hunt.UserHunt;
import com.yanqu.road.entity.hunt.UserHuntPatronsData;
import com.yanqu.road.entity.log.LogHuntBattle;
import com.yanqu.road.entity.log.LogHuntKill;
import com.yanqu.road.entity.player.UserPatrons;
import com.yanqu.road.entity.union.UserUnionChamberData;
import com.yanqu.road.entity.union.cross.CrossUnionChamberPatrons;
import com.yanqu.road.entity.union.cross.CrossUnionMember;
import com.yanqu.road.logic.bussiness.player.UserHuntBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.pb.hunt.HuntProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.patrons.PatronsModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.gameplayer.module.union.cross.CrossUnionModule;
import com.yanqu.road.server.manger.config.HuntConfigMgr;
import com.yanqu.road.server.manger.config.PatronsMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.hunt.HuntMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.manger.log.LogMgr;
import com.yanqu.road.server.manger.rank.RankMgr;
import com.yanqu.road.server.manger.union.CrossUnionMgr;
import com.yanqu.road.server.pb.HuntPb;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.LocalDateTimeHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class HuntModule extends GeneralModule {

    private UserHunt userHunt;

    private Map<Integer, UserHuntPatronsData> userHuntPatronsDataMap;

    public HuntModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        userHunt = UserHuntBussiness.getUserHunt(player.getUserId());
        userHuntPatronsDataMap = UserHuntBussiness.getUserHuntPatronsDataMap(player.getUserId());
        checkUserHuntPatronsMap();
        return true;
    }

    @Override
    public boolean afterLoadData() {
        if(SystemOpenMgr.systemOpen(player, eSystemId.Hunt.getValue())){
            initUserHunt();
        }
        return false;
    }

    @Override
    public boolean saveData() {
        if(null != userHunt){
            if(userHunt.isInsertOption()){
                UserHuntBussiness.addUserHunt(userHunt);
            }else if(userHunt.isUpdateOption()){
                UserHuntBussiness.updateUserHunt(userHunt);
            }
        }
        for(UserHuntPatronsData userHuntPatronsData : userHuntPatronsDataMap.values()){
            if(userHuntPatronsData.isInsertOption()){
                UserHuntBussiness.addUserHuntPatronsData(userHuntPatronsData);
            }else if(userHuntPatronsData.isUpdateOption()){
                UserHuntBussiness.updateUserHuntPatronsData(userHuntPatronsData);
            }
        }
        return true;
    }

    @Override
    public void afterLogin() {
        syncHuntBoxData();
        syncHuntData();
        checkUserHuntPatronsMap();
        syncUserHuntPatronsData(new ArrayList<>(userHuntPatronsDataMap.values()));
    }

    @Override
    public void loginSendMsg() {

    }

    public void resetOneDay(){
        if(null == userHunt){
            return;
        }
        long zeroTime = LocalDateTimeHelper.getZeroTimeTimeStamp() / 1000;
        if(zeroTime > userHunt.getModifyTime()){
            userHunt.setMonsterIndex(0);
            userHunt.setMonsterLoseBlood(BigInteger.ZERO);
            userHunt.setOpenBoxTimes(0);
            userHunt.setOpenHuntBoxUidList(new ArrayList<>());
            userHunt.setModifyTime(zeroTime);
            syncHuntBoxData();
            syncHuntData();
        }
        List<UserHuntPatronsData> syncList = new ArrayList<>();
        for(UserHuntPatronsData userHuntPatronsData : userHuntPatronsDataMap.values()){
            if(zeroTime > userHuntPatronsData.getModifyTime()){
                userHuntPatronsData.setBattleTimes(0);
                userHuntPatronsData.setSacrificeAttackTimes(0);
                userHuntPatronsData.setModifyTime(zeroTime);
                syncList.add(userHuntPatronsData);
            }
        }
        if(syncList.size() > 0){
            syncUserHuntPatronsData(syncList);
        }
    }

    private void initUserHunt(){
        if(null == userHunt){
            UserHunt tempHunt = new UserHunt();
            tempHunt.setUserId(player.getUserId());
            tempHunt.setMonsterIndex(0);
            tempHunt.setMonsterLoseBlood(BigInteger.ZERO);
            tempHunt.setModifyTime(System.currentTimeMillis() / 1000);
            tempHunt.setHuntScore(BigInteger.ZERO);
            tempHunt.setOpenHuntBoxUidList(new ArrayList<>());
            tempHunt.setInsertOption();
            userHunt = tempHunt;
        }
    }

    private void syncHuntData(){
        HuntProto.HuntDataMsg.Builder msg = HuntPb.parseHuntDataMsg(userHunt);
        if(null != msg){
            player.sendPacket(Protocol.U_HUNT_DATA_SYNC, msg);
        }
    }

    public void syncHuntBoxData(){
        HuntProto.HuntBoxDataMsg.Builder msg = HuntPb.parseHuntBoxDataMsg(userHunt);
        if(null != msg){
            player.sendPacket(Protocol.U_HUNT_BOX_DATA_SYNC, msg);
        }
    }

    private void syncUserHuntPatronsData(List<UserHuntPatronsData> userHuntPatronsDataList){
        player.sendPacket(Protocol.U_HUNT_PATRONS_SYNC, HuntPb.parseHuntPatronsDataListMsg(player, userHuntPatronsDataList));
    }

    private void syncUserHuntPatronsData(UserHuntPatronsData userHuntPatronsData){
        if(null != userHuntPatronsData){
            List<UserHuntPatronsData> syncList = new ArrayList<>();
            syncList.add(userHuntPatronsData);
            syncUserHuntPatronsData(syncList);
        }
    }

    public HuntBattleResult huntBattle(int type, int patronsId, long chamberUserId){
        HuntBattleResult result = new HuntBattleResult();
        if(!SystemOpenMgr.systemOpen(player, eSystemId.Hunt.getValue())){
            result.setRet(GameErrorCode.E_SYSTEM_NO_OPEN);
            return result;
        }
        if(!HuntConfigMgr.isHuntSystemOpenTime()){
            result.setRet(GameErrorCode.E_SYSTEM_NO_OPEN);
            return result;
        }
        if(!HuntConfigMgr.isInHuntBattleTime()){
            result.setRet(GameErrorCode.E_HUNT_NO_BATTLE_TIME);
            return result;
        }
        if(HuntConfigMgr.isTodayHuntFinish(userHunt.getMonsterIndex())){
            result.setRet(GameErrorCode.E_HUNT_TODAY_FINISH);
            return result;
        }
        BigInteger ability = BigInteger.ZERO;
        boolean isChamber = false;
        if(1 == type){
            CrossUnionChamberPatrons chamberPatrons;
            isChamber = true;
            String unionUid = player.getUserInfo().getUnionUid();
            if(StringUtils.isNullOrEmpty(unionUid)){
                result.setRet(GameErrorCode.E_UNION_NO_JOIN_UNION);
                return result;
            }
            UserUnionChamberData userUnionChamberData = player.getModule(CrossUnionModule.class).getUserUnionChamberData();
            if(null == userUnionChamberData){
                result.setRet(GameErrorCode.E_SYSTEM_NO_OPEN);
                return result;
            }
            if(userUnionChamberData.getUseHuntCount() >= GameConfig.UNION_CHAMBER_USE_HUNT_MAX_COUNT){
                player.getModule(CrossUnionModule.class).syncChamberData();       //超过次数了，同步一下数据给客户端
                result.setRet(GameErrorCode.E_UNION_CHAMBER_HUNT_OVER_TIMES);
                return result;
            }
            if(player.getUserId() == chamberUserId){
                result.setRet(GameErrorCode.E_UNION_CHAMBER_HUNT_NO_SELF);
                return result;
            }
            CrossUnionMember unionMember = CrossUnionMgr.getUnionMember(unionUid, chamberUserId);
            if(null == unionMember){
                result.setRet(GameErrorCode.E_UNION_CHAMBER_NO_DISPATCH);
                return result;
            }
            chamberPatrons = unionMember.getChamberPatrons();
            if(null == chamberPatrons){
                result.setRet(GameErrorCode.E_UNION_CHAMBER_NO_DISPATCH);
                return result;
            }
            if(chamberPatrons.getPatronsId() != patronsId){
                result.setRet(GameErrorCode.E_UNION_CHAMBER_DISPATCH_PATRONS_HAS_CHANGE);
                return result;
            }
            userUnionChamberData.addUseHunt(chamberUserId);
            player.getModule(CrossUnionModule.class).syncChamberData();
            ability = chamberPatrons.getAbility();
        }else {
            UserPatrons userPatrons = player.getModule(PatronsModule.class).getUserPatrons(patronsId);
            if (null == userPatrons) {
                result.setRet(GameErrorCode.E_PATRONS_NO_FOUND);
                return result;
            }
            UserHuntPatronsData userHuntPatronsData = getUserHuntPatronsData(patronsId);
            if (null == userHuntPatronsData) {
                notifyAddPatrons(userPatrons);
                userHuntPatronsData = getUserHuntPatronsData(patronsId);
                if (null == userHuntPatronsData) {
                    result.setRet(GameErrorCode.E_PATRONS_NO_FOUND);
                    return result;
                }
            }
            int maxBattleTimes = HuntConfigMgr.getPatronsMaxHuntBattleTimes(player, userHuntPatronsData.getPatronsId());
            if (userHuntPatronsData.getBattleTimes() >= maxBattleTimes) {
                syncUserHuntPatronsData(userHuntPatronsData);         //超过次数了，同步一下数据给客户端
                result.setRet(GameErrorCode.E_HUNT_PATRONS_BATTLE_TIMES_OVER);
                return result;
            }
            userHuntPatronsData.setBattleTimes(userHuntPatronsData.getBattleTimes() + 1);
            ability = userPatrons.getAbility();
        }
        HuntMonster huntMonster = HuntConfigMgr.getHuntMonster(userHunt.getMonsterIndex());
        int monsterIndex = userHunt.getMonsterIndex();

        BigInteger monsterBlood = huntMonster.getBlood().subtract(userHunt.getMonsterLoseBlood()).subtract(ability);
        boolean isKill = false;
        if(ability.add(userHunt.getMonsterLoseBlood()).compareTo(huntMonster.getBlood()) < 0){
            userHunt.setMonsterLoseBlood(userHunt.getMonsterLoseBlood().add(ability));
        }else {
            isKill = true;
            BigInteger oldScore = userHunt.getHuntScore();
            userHunt.setMonsterIndex(userHunt.getMonsterIndex() + 1);
            if (userHunt.getMaxLevel() < userHunt.getMonsterIndex()){
                userHunt.setMaxLevel(userHunt.getMonsterIndex());
            }
            userHunt.setMonsterLoseBlood(BigInteger.ZERO);
            Property reward = HuntConfigMgr.getHuntMonsterReward(player, huntMonster);
            int huntBoxId = HuntConfigMgr.getRandomHuntBoxId(huntMonster);
            if(huntBoxId > 0){//获得随机宝箱
                HuntBox huntBox = HuntMgr.addHuntBox(player, huntBoxId);
                if(null != huntBox) {
                    reward.addProperty(PropertyHelper.parseStringToProperty(GameConfig.HUNT_BOX_OWNER_REWARD));
                    result.setHuntBoxUid(huntBox.getHuntBoxUid());
                    result.setHuntBoxGoodsId(huntBox.getGoodsBoxId());
                }
            }
            player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.Hunt, eLogMoneyType.HuntMonster);
            result.setReward(PropertyHelper.parsePropertyToString(reward));
            AutoLogMgr.add(new LogHuntKill(player.getUserId(), userHunt.getMonsterIndex(), result.getHuntBoxUid(), result.getReward(), oldScore, userHunt.getHuntScore()));
        }
        AutoLogMgr.add(new LogHuntBattle(player.getUserId(), monsterIndex, patronsId, isChamber, chamberUserId, ability, monsterBlood, isKill));
        return result;
    }

    public void initHuntSystem(){
        initUserHunt();
        syncHuntBoxData();
        syncHuntData();
        checkUserHuntPatronsMap();
        syncUserHuntPatronsData(new ArrayList<>(userHuntPatronsDataMap.values()));
    }

    public void notifyAddPatrons(UserPatrons userPatrons){
        if(SystemOpenMgr.systemOpen(player, eSystemId.Hunt.getValue())) {
            UserHuntPatronsData patronsData = getUserHuntPatronsData(userPatrons.getPatronsId());
            if (null != patronsData) {
                syncUserHuntPatronsData(patronsData);
            }
        }
    }

    public void notifyPatronsStage(UserPatrons userPatrons){
        if(SystemOpenMgr.systemOpen(player, eSystemId.Hunt.getValue())) {
            UserHuntPatronsData patronsData = getUserHuntPatronsData(userPatrons.getPatronsId());
            if (null != patronsData) {
                syncUserHuntPatronsData(patronsData);
            }
        }
    }

    private UserHuntPatronsData getUserHuntPatronsData(int patronsId){
        initUserHuntPatronsData(patronsId);
        return userHuntPatronsDataMap.get(patronsId);
    }

    private void checkUserHuntPatronsMap(){
        if(SystemOpenMgr.systemOpen(player, eSystemId.Hunt.getValue()) || SystemOpenMgr.systemOpen(player, eSystemId.Sacrifice.getValue())){
            Map<Integer, UserPatrons> patronsMap = player.getModule(PatronsModule.class).getUserPatronsMap();
            for(UserPatrons userPatrons : patronsMap.values()){
                if(!userHuntPatronsDataMap.containsKey(userPatrons.getPatronsId())){
                    initUserHuntPatronsData(userPatrons.getPatronsId());
                }
            }
        }
    }

    private void initUserHuntPatronsData(int patronsId) {
        if(!userHuntPatronsDataMap.containsKey(patronsId) && player.getModule(PatronsModule.class).getUserPatronsMap().containsKey(patronsId)){
            UserHuntPatronsData userHuntPatronsData = new UserHuntPatronsData();
            userHuntPatronsData.setUserId(player.getUserId());
            userHuntPatronsData.setPatronsId(patronsId);
            userHuntPatronsData.setBattleTimes(0);
            userHuntPatronsData.setModifyTime(System.currentTimeMillis() / 1000);
            userHuntPatronsData.setInsertOption();
            userHuntPatronsDataMap.put(userHuntPatronsData.getPatronsId(), userHuntPatronsData);
        }
    }

    public UserHunt getUserHunt() {
        return userHunt;
    }

    public void addHuntScore(int huntScore){
        if(null == userHunt){
            return;
        }
        userHunt.setHuntScore(userHunt.getHuntScore().add(BigInteger.valueOf(huntScore)));
        RankMgr.changeUserRank(eBigRankType.Normal.getValue(), player.getUserId(), userHunt.getHuntScore(), eRankType.HuntScore.getValue(), "");
    }

    public int recoveryHuntScore(int day, int discount) {
        Property scoreReward = new Property();
        int maxLevel = userHunt.getMaxLevel();
        if (maxLevel == 0){
            return 0;
        }
        int huntWavesCount = HuntConfigMgr.getHuntWavesCount();
        if (maxLevel > huntWavesCount){
            maxLevel = huntWavesCount;
        }
        for (int index = 0; index < maxLevel; index++) {
            HuntMonster huntMonster = HuntConfigMgr.getHuntMonster(index);
            scoreReward.addProperty(huntMonster.getReward());
        }

        int finalReward = scoreReward.getCountByGoodsId(GameConfig.GAME_MONEY_HUNT_SCORE).intValue() * day * discount / 1000;
        scoreReward.setGood(GameConfig.GAME_MONEY_HUNT_SCORE,BigInteger.valueOf(finalReward));
        player.getModule(CurrencyModule.class).addCurrency(scoreReward, eLogMoneyType.RecoveryReward, eLogMoneyType.HuntMonster);
        return finalReward;
    }

}
